import os
import core_analysis
import sys
import shutil
cwd = os.path.split(os.path.realpath(__file__))[0]
sys.path.append(os.path.join(cwd, "../config/"))
sys.path.append(os.path.join(cwd, "../networking/"))
import config
import time
import client
import glob
from time import clock, time

class ProcessCores():
    def __init__(self):
        """
        initialize configuration and other helper classes
        """
        self.gdb = None
        self.client = client.Client()
        self.cfsize = core_analysis.CoreFileSize()
        self.config = config.Config()
        self.crash = core_analysis.Crash()
        self.config.parse()
        trunk = os.path.join(cwd, "../../")
        self.results_dir = os.path.abspath(os.path.join(trunk, "client/results"))
        self.mutation_folder = os.path.abspath(os.path.join(trunk, self.config.config["mutation_folder"]))
        self.fuzz_prog_folder = os.path.abspath(os.path.join(trunk, self.config.config["fuzzing_prog_folder"]))        
   
    def process_cores(self):
        """
        process core files generated by fuzzing application
        """
        #get unique core files using filesize technique
        #unique_cores = self.cfsize.get_unique_cores(self.fuzz_prog_folder)
        self.gdb = core_analysis.CoreGDB()
        unique_cores = self.gdb.get_cores(self.fuzz_prog_folder)


###############################################################################
# Process Cores Using Frame Tracing
###############################################################################
#        try:
#            if self.gdb:
#                if not self.gdb.gdb_is_alive():
#                    self.gdb = core_analysis.CoreGDB()
#                    self.gdb.start_gdb()
#            else:
#                self.gdb = core_analysis.CoreGDB()
#                self.gdb.start_gdb()
#            unique_cores = self.gdb.get_unique_cores(self.fuzz_prog_folder)
#        except: 
#            print "GDB Crashed"
###############################################################################

        
        #process unique core files 
        for unique_core in unique_cores:
            shutil.copy(unique_core, self.config.results_dir)
            crash_file = self.crash.get_file_that_cause_crash(unique_core, self.mutation_folder)
            shutil.copy(crash_file, self.config.results_dir)

    def process_core_bts(self):
        """
        Get backtraces of crashes and hash the function names to identify unique crashes. The results will be 
        written to ".results" files. These files will in turn be parsed and the information sent to a centralized server  
        """
        #get unique client identification number
        dfuzz_id = self.config.get_dfuzz_id()
        #get unique core files using filesize technique
        #unique_cores = self.cfsize.get_unique_cores(self.results_dir)
        unique_cores = glob.glob(os.path.join(self.results_dir, "core.*"))
        #process unique core files 
        for unique_core in unique_cores:
            crash_file = self.crash.get_file_that_cause_crash(unique_core, self.mutation_folder)
            #get unique crash hash (ie. hash of backtraces from core files
            crash_hash = ""
            try:
                gdb = core_analysis.CoreGDB()
                gdb.start_gdb()
                gdb.set_program(self.config.config["fuzzed_program"])
                gdb.set_core_file(unique_core)
                backtrace = gdb.get_backtrace()
                crash_hash = gdb.get_unique_crash_hash(backtrace)
            except:
                print "GDB FAILED To Process Core Files"
            #output unique crash results file    
            results_file = os.path.splitext(crash_file)[0]
            results_file = os.path.split(results_file)[1]+".results"
            results_file = os.path.join(self.config.results_dir, results_file)
            r_fh = open(results_file, "w")
            crash_filename = os.path.join(self.config.results_dir, os.path.split(crash_file)[1])
            r_fh.write(dfuzz_id+"|"+crash_hash+"|"+ crash_filename + "|" + unique_core)
            r_fh.close()        
    
    def report_results(self, new_files):
        """
        @param new_files: new files that exist in results directory
        """
        for file in new_files: 
            if ".results" in file: 
                results_fh = open(os.path.join(self.results_dir, file), "r")
                data = results_fh.read()
                self.client.send(data)
                results_fh.close()
                
if __name__ == "__main__":
    p = ProcessCores()
    p.process_cores()        
    p.process_core_bts()
    #p.report_results(["/home/username/workspace/dfuzz/trunk/client/results/4002992-7.results"])